package com.kysd.uploadfile.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.google.gson.Gson;
import com.kysd.base.ApiModel;
import com.kysd.base.BaseController;
import com.kysd.base.Common;
import com.kysd.uploadfile.common.RedisKeyCommon;
import com.kysd.uploadfile.exception.UploadException;
import com.kysd.uploadfile.redis.RedisUtil;
import com.kysd.uploadfile.vo.UploadFileVO;
import com.kysd.uploadfile.vo.UploadMultipleFileVO;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Client;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;

/**
 * 上传文件
 * 
 * @author liangjinquan
 *
 */
@RestController
@RequestMapping(value = "/uploadfile")
public class UploadFileController extends BaseController{

	@Value("${qiniu.bucketName}")
	private String bucketName;
	@Value("${qiniu.ACCESS_KEY}")
	private String ACCESS_KEY;
	@Value("${qiniu.SECRET_KEY}")
	private String SECRET_KEY;
	@Value("${qiniu.dumain}")
	private String dumain;

	@Autowired
	private RedisUtil redisUtil;

	/**
	 *  上传单个文件
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping("upload")
	@SuppressWarnings("unchecked")
	public ApiModel<Object> uploadFile(HttpServletRequest request, HttpServletResponse response) {
		
		try {
				// 解决跨域问题
				cross(response);
				// 过滤黑白名单
		//		filter(request);
				
				// 获取从前台传过来得图片
				MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
				MultipartFile multipartFile = req.getFile("file");
				
				// 根据获取到的文件类型截取出图片后缀
				String type = returnFileSuffix(multipartFile);
				
				// 校验文件类型和大小
				checkFileTypeAndLength(multipartFile, type);

				String fileName = uploadFileQiNiu(createFileName(multipartFile, type), multipartFile);
				// 文件全路径
				String fileUrl = dumain + fileName;
				
				// 校验数据安全 
				// block：表示系统确认审核内容违规，建议您将其删除。
				// review：表示系统无法确认审核内容是否违规，建议您进行人工复核。pass：表示系统确认审核内容正常，建议您忽略该文件。
				String suggestion = "pass";
//				suggestion = dataImageCheck(fileUrl);
				
				return SUCCESS(0, "操作成功", new UploadFileVO(fileUrl, suggestion));
			} catch (UploadException e) {
				e.printStackTrace();
				return new ApiModel<Object>(e.getStatus(), e.getMessage());
			} catch (Exception e) {
				e.printStackTrace();
				return FAIL();
			}
	}
	
	/**
	 * 批量上传文件
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping("uploadMultipleFiles")
	@SuppressWarnings("unchecked")
	public ApiModel<Object> uploadMultipleFiles(HttpServletRequest request, HttpServletResponse response){
		// 解决跨域问题
		cross(response);
		// 获取从前台传过来得图片
		MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
		List<MultipartFile> multipartFiles = req.getFiles("file");
		List<UploadMultipleFileVO> uploadFileList = new ArrayList<UploadMultipleFileVO>();
		for(MultipartFile multipartFile : multipartFiles) {
			try {
				// 根据获取到的文件类型截取出图片后缀
				String type = returnFileSuffix(multipartFile);
				// 校验文件类型和大小
				checkFileTypeAndLength(multipartFile, type);
				String fileName = uploadFileQiNiu(createFileName(multipartFile, type), multipartFile);
				// 文件全路径
				String fileUrl = dumain + fileName;
				// 内容安全校验
				String suggestion = "pass";
				suggestion = dataImageCheck(fileUrl);
				
				// 记录上传成功的返回
				uploadFileList.add(new UploadMultipleFileVO(fileUrl, suggestion));
				
			} catch (UploadException e) {
				e.printStackTrace();
				uploadFileList.add(new UploadMultipleFileVO(null, Common.UPLOAD_FILE_FAIL, null, e.getMessage()));
			} catch (Exception e) {
				e.printStackTrace();
				uploadFileList.add(new UploadMultipleFileVO(null, Common.UPLOAD_FILE_FAIL, null, "系统异常,请联系管理员"));
			}
		}
		return SUCCESS(uploadFileList);
	}
	
	/**
	 * 返回文件类型后缀
	 * @param multipartFile
	 * @return
	 */
	private String returnFileSuffix(MultipartFile multipartFile) {
		// 获取图片的文件类型
		String houzhu = multipartFile.getContentType();
		int one = houzhu.lastIndexOf("/");
		// 根据获取到的文件类型截取出图片后缀
		String type = houzhu.substring((one + 1), houzhu.length());
		return type;
	}
	
	/**
	 * 校验文件类型和大小
	 * @param multipartFile
	 * @param type
	 */
	public void checkFileTypeAndLength(MultipartFile multipartFile, String type)throws UploadException{
		if(redisUtil.hexists(Common.FILE_TYPE_KEY, type)) {
			Object value = redisUtil.hget(Common.FILE_TYPE_KEY, type);
			Long maxLength = Long.valueOf(value.toString());
			if(maxLength.compareTo(multipartFile.getSize()) < 0) {
				throw new UploadException("上传."+type+"后缀文件,不能超过"+maxLength+"字节");
			}
		}else {
			throw new UploadException("不允许上传."+type+"后缀文件");
		}
	}

	/**
	 * 拦截（ip、文件类型、大小过滤)
	 * 
	 * @param request
	 */
	private void filter(HttpServletRequest request)throws UploadException {
		String ip = getIpAddress(request);
		
		// ip过滤
		
	}

	/**
	 * 获取IP
	 * @param request
	 * @return
	 */
	private String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	/**
	 * 数据校验
	 * 
	 * @param fileUrl
	 */
	private String dataImageCheck(String fileUrl)throws UploadException {
		// 图片校验
		String url = "http://ai.qiniuapi.com/v3/image/censor";
		String host = "ai.qiniuapi.com";
		String body = "{ \"data\": { \"uri\": \"" + fileUrl
				+ "\" }, \"params\": { \"scenes\": [ \"pulp\", \"terror\", \"politician\" ] } }";
		String contentType = "application/json";
		String method = "POST";
		Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
		String qiniuToken = "Qiniu " + auth.signRequestV2(url, method, body.getBytes(), contentType);
		// 头部部分
		StringMap header = new StringMap();
		header.put("Host", host);
		header.put("Authorization", qiniuToken);
		header.put("Content-Type", contentType);
		Configuration c = new Configuration(Region.huadong());
		Client client = new Client(c);
		try {
			Response response = client.post(url, body.getBytes(), header, contentType);
			Gson gson = new Gson();
			Map<String, Object> map = gson.fromJson(response.bodyString(), Map.class);
			Map linkedTreeMap = (Map) map.get("result");
			return (String) linkedTreeMap.get("suggestion");
		} catch (QiniuException e) {
			e.printStackTrace();
			return null;
		}

		// 视频校验
	}

	/**
	 * 解决跨域问题
	 * 
	 * @param response
	 */
	private void cross(HttpServletResponse response) {
		// // 指定允许其他域名访问
		response.addHeader("Access-Control-Allow-Origin", "*");
		response.addHeader("Access-Control-Allow-Credentials", "true");
		// 响应类型
		response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, OPTIONS, DELETE");
		// 响应头设置
		response.setHeader("Access-Control-Allow-Headers",
				"Content-Type, x-requested-with, X-Custom-Header, HaiYi-Access-Token,token");
	}

	/**
	 * 创建图片名称
	 * 
	 * @param multipartFile
	 * @param type          文件后缀
	 * @return
	 */
	private String createFileName(MultipartFile multipartFile, String type) {

		int x = (int) (Math.random() * 1000);
		// 获取到当前的日期时间用户生成文件名防止文件名重复
		String filedata = this.dates();
		StringBuffer sb = new StringBuffer();
		sb.append("kysd");
		sb.append(x);
		sb.append(filedata);
		sb.append(".");
		sb.append(type);
		return sb.toString();
	}

	/**
	 * 调用七牛上传文件
	 * 
	 * @param file
	 * @param multipartFile
	 */
	private String uploadFileQiNiu(String filename, MultipartFile multipartFile) throws Exception {
		Object token = redisUtil.get(RedisKeyCommon.TOKEN);
		String uptoken = null;
		if (null == token) {
			Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
			// token时效一小时
			uptoken = auth.uploadToken(bucketName);
			// 时效小于1小时即可
			redisUtil.set(RedisKeyCommon.TOKEN, uptoken, 3500);
		} else {
			uptoken = String.valueOf(token);
		}

		Configuration cfg = new Configuration(Region.region2());
		// ...其他参数参考类注释
		UploadManager uploadManager = new UploadManager(cfg);
		// ...生成上传凭证，然后准备上传
		Response response = uploadManager.put(multipartFile.getBytes(), filename, uptoken);
		// 解析上传成功的结果
		DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
		return putRet.key;
	}

	/**
	 * 获取当前日期时间的string类型用于文件名防重复
	 * 
	 * @return
	 */
	private String dates() {
		Date currentTime = new Date();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
		String dateString = formatter.format(currentTime);
		return dateString;
	}
}
